package climit

import (
	"fmt"
	"runtime"
)

type Set[E ~int | ~string] interface {
	Contains(e E) bool
	Add(e E)
}

type set[E ~int | ~string] struct {
	items map[E]struct{}
}

func (it *set[E]) Contains(element E) bool {
	_, ok := it.items[element]
	return ok
}

func (it *set[E]) Add(element E) {
	it.items[element] = struct{}{}
}

func SetOf[E ~int | ~string](items []E) Set[E] {
	result := set[E]{
		items: make(map[E]struct{}),
	}
	if items != nil && len(items) > 0 {
		for _, value := range items {
			result.items[value] = struct{}{}
		}
	}
	return &result
}

func MakeSet[E ~int | ~string]() Set[E] {
	return &set[E]{
		items: make(map[E]struct{}),
	}
}

// ReadLineFromTerminal 从终端读取一行
func ReadLineFromTerminal() string {
	var c byte
	var err error
	var b []byte

	for err == nil {
		_, err = fmt.Scanf("%c", &c)
		if c != '\n' {
			b = append(b, c)
		} else {
			break
		}
	}

	if len(b) == 0 {
		return ""
	}
	// 兼容windows平台下的会车符，windows下的会车是 \r\n
	if runtime.GOOS == "windows" && b[len(b)-1] == '\r' {
		b = b[:len(b)-1]
	}

	return string(b)
}

// GetDisplayString 获取展示字符串，
// displayWidth 是要展示的宽度
// fillWith 是填充字符串，必须是半角的
// fillToLeft 是否填充到左侧，false的话会填充到右侧
func GetDisplayString(str string, displayWidth int, fillWith rune, fillToLeft bool) string {
	if !IsSBC(fillWith) {
		fmt.Println("fillWith 必须是一个半角字符")
	}
	fillWithStr := string(fillWith)
	minDisplayWidth := GetDisplayWidth(str)
	if displayWidth <= minDisplayWidth {
		return str
	}
	if fillToLeft {
		for i := displayWidth - minDisplayWidth; i > 0; i-- {
			str = fillWithStr + str
		}
	} else {
		for i := displayWidth - minDisplayWidth; i > 0; i-- {
			str = str + fillWithStr
		}
	}
	return str
}

// GetMaxDisplayWidth 获取字符串列表中所有字符串的最大展示宽度
func GetMaxDisplayWidth(strArray []string) int {
	if strArray == nil {
		return 0
	}
	maxDisplayWidth := 0
	for _, str := range strArray {
		displayWidth := GetDisplayWidth(str)
		if displayWidth > maxDisplayWidth {
			maxDisplayWidth = displayWidth
		}
	}
	return maxDisplayWidth
}

// GetDisplayWidth 获取字符串在终端中的展示宽度，全角占两位，半角占一位
func GetDisplayWidth(str string) int {
	if str == "" {
		return 0
	}

	displayWidth := 0
	for _, char := range str {
		if IsSBC(char) {
			displayWidth++
		} else {
			displayWidth += 2
		}
	}
	return displayWidth
}

// IsSBC 判断一个字符是否是半角字符
func IsSBC(c rune) bool {
	switch {
	case c <= 0x007E:
	case c == 0x00A2 || c == 0x00A3:
	case c == 0x00A5 || c == 0x00A6:
	case c == 0x00AC || c == 0x00AF:
	case c == 0x20A9:
	case c == 0x2985 || c == 0x2986:
	case c >= 0xFF61 && c <= 0xFF9F:
	case c >= 0xFFA0 && c <= 0xFFBE:
	case c >= 0xFFC2 && c <= 0xFFC7:
	case c >= 0xFFCA && c <= 0xFFCF:
	case c >= 0xFFD2 && c <= 0xFFD7:
	case c >= 0xFFDA && c <= 0xFFDC:
	case c >= 0xFFE8 && c <= 0xFFEE:
	default:
		return false
	}
	return true
}
